package account

import (
	"errors"
	"fmt"
	"hft/Database/admin"
	"hft/Database/admin/file"
	"hft/Http/Models/dao"
	"hft/Http/Models/request"
	"hft/Http/Models/response"
	"hft/Http/Services/base"
	utils "hft/Http/Utils"
	"hft/e"
	"hft/global"
	"hft/tools"
	wapi "hft/tools/weixin/api"
	"regexp"

	"gorm.io/gorm"
)

type Account struct{}

func (a *Account) AddAccount(claims tools.BaseClaims, account *request.Account) (err error) {

	var nowRole *admin.Role
	err2 := tools.AliyunSmsTool.VerifyValid(global.OC_CONFIG.AliyunSms.AddAccountSend, account.Phone, account.Code)

	if err2 != nil {
		return err2
	}

	// res1, err1 := tools.ValidIDCard(account.IDCard, account.RealName)

	// if res1.Data.ResponseCode != "0" {
	// 	return errors.New(e.IDCardNotPass)
	// }

	// if err1 != nil {
	// 	return errors.New(e.InValidInfo)
	// }

	err = global.OC_DB.Transaction(func(tx *gorm.DB) error {

		parentAccount, err := base.FindAccount(claims, tx)

		if err != nil {
			return err
		}

		var role *admin.Role

		err = tx.First(&role, parentAccount.RoleId).Error

		if err != nil {
			return errors.New(e.RoleNotExist)
		}

		err = tx.Where("id = ?", account.RoleId).First(&nowRole).Error

		if err != nil {
			return errors.New(e.RoleNotExist)
		}

		match, _ := regexp.MatchString(fmt.Sprintf("^%v%v,", role.Link, role.ID), nowRole.Link)

		if !match {
			return errors.New(e.CanOperaThisRole)
		}

		var newAccount = &admin.Account{
			Username:    account.Username,
			PID:         parentAccount.ID,
			AccountLink: fmt.Sprintf("%v%v,", parentAccount.AccountLink, parentAccount.ID),
			Belong:      1,
			RoleName:    nowRole.RoleName,
			RoleId:      nowRole.ID,
			Status:      account.Status,
			Phone:       account.Phone,
			IDCard:      account.IDCard,
			RealName:    account.RealName,
			RegionLink:  account.RegionLink,
			OpenId:      "",
			Qrcode:      "",
			Link:        nowRole.Link,
		}

		res := tx.Model(&admin.Account{}).Where("username = ?", account.Username).Or("phone = ?", account.Phone).FirstOrCreate(&newAccount)

		if res.RowsAffected == 0 {
			return errors.New(e.AccountHasExit)
		}

		if res.Error != nil {
			return errors.New(e.InValidInfo)
		}
		// 创建目录
		// fileopera.CreateDirSystem(account.Username)
		// fileopera.CreateRoot(account.Username)
		var newAccounta *admin.Account
		err = tx.Select("username,id").Where("username = ?", account.Username).First(&newAccounta).Error
		if err != nil {
			return errors.New(e.AccountNotExist)
		}
		var dir = &file.Dir{
			AccountID: newAccounta.ID,
			Link:      ",",
		}
		err = tx.Create(&dir).Error
		if err != nil {
			return errors.New(e.ErrorInfo)
		}
		return nil

	})

	return err
}

func (a *Account) EditAccount(claims tools.BaseClaims, account *request.Account) (err error) {

	parentAccount, err := base.FindAccount(claims, global.OC_DB)
	if err != nil {
		return nil
	}

	var nowAccount *admin.Account
	err = global.OC_DB.First(&nowAccount, account.ID).Error
	if err != nil {
		return errors.New(e.AccountNotExist)
	}

	match, _ := regexp.MatchString(fmt.Sprintf("^%v", parentAccount.AccountLink), nowAccount.AccountLink)
	if !match {
		return errors.New(e.NoRightToOpera)
	}

	res := global.OC_DB.Model(&admin.Account{}).Where("id = ?", nowAccount.ID).Updates(map[string]interface{}{
		"username": account.Username,
		"sort":     account.Sort,
		"status":   account.Status,
	})
	if res.RowsAffected == 0 {
		return errors.New(e.AccountHasExit)
	}
	if res.Error != nil {
		return errors.New(e.InValidInfo)
	}

	return nil

}

// 手机验证
func (a *Account) ChangePhone(claims tools.BaseClaims, account *request.Account) (err error) {

	parentAccount, err := base.FindAccount(claims, global.OC_DB)
	if err != nil {
		return nil
	}

	var nowAccount *admin.Account
	err = global.OC_DB.First(&nowAccount, account.ID).Error
	if err != nil {
		return errors.New(e.AccountNotExist)
	}

	match, _ := regexp.MatchString(fmt.Sprintf("^%v", parentAccount.AccountLink), nowAccount.AccountLink)
	if !match {
		return errors.New(e.NoRightToOpera)
	}

	err2 := tools.AliyunSmsTool.VerifyValid("ADD_ACCOUNT_", account.Phone, account.Code)

	if err2 != nil {
		return err2
	}

	res := global.OC_DB.Model(&admin.Account{}).Where("id = ?", nowAccount.ID).Updates(map[string]interface{}{
		"phone": account.Phone,
	})
	if res.RowsAffected == 0 {
		return errors.New(e.AccountHasExit)
	}
	if res.Error != nil {
		return errors.New(e.InValidInfo)
	}

	return nil

}

func (a *Account) ChangeIDCard(claims tools.BaseClaims, account *request.Account) (err error) {
	parentAccount, err := base.FindAccount(claims, global.OC_DB)
	if err != nil {
		return nil
	}

	var nowAccount *admin.Account
	err = global.OC_DB.First(&nowAccount, account.ID).Error
	if err != nil {
		return errors.New(e.AccountNotExist)
	}

	match, _ := regexp.MatchString(fmt.Sprintf("^%v", parentAccount.AccountLink), nowAccount.AccountLink)
	if !match {
		return errors.New(e.NoRightToOpera)
	}

	res1, err1 := tools.ValidIDCard(account.IDCard, account.RealName)

	if res1.Data.ResponseCode != "0" {
		return errors.New(e.IDCardNotPass)
	}

	if err1 != nil {
		return errors.New(e.InValidInfo)
	}

	res := global.OC_DB.Model(&admin.Account{}).Where("id = ?", nowAccount.ID).Updates(map[string]interface{}{
		"id_card": account.IDCard,
	})
	if res.RowsAffected == 0 {
		return errors.New(e.AccountHasExit)
	}
	if res.Error != nil {
		return errors.New(e.InValidInfo)
	}

	return nil

}

func (a *Account) GetAccountInfo(claims tools.BaseClaims) (account *response.AccountInfo, err error) {

	var SearchAccount *admin.Account

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).Preload("Role").First(&SearchAccount).Error

	if err != nil {
		return nil, errors.New("无该账号信息")
	}

	belongName := dao.GetBelongDao.GetBelongFromAccount(SearchAccount.RegionLink, global.OC_DB)

	var data = &response.AccountInfo{
		Username: SearchAccount.Username,
		Avatar:   SearchAccount.Avatar,
		// NickName: SearchAccount.NickName,
		Phone:    SearchAccount.Phone,
		Belong:   belongName,
		Prefix:   global.OC_CONFIG.AliyunOSS.BucketUrl,
		RoleName: SearchAccount.Role.RoleName,
	}

	return data, err
}

func (a *Account) GetAccountList(claims tools.BaseClaims, paginate *request.AccountPage) (data *utils.Page, err error) {

	var SearchAccount *admin.Account

	var accounts []*admin.Account

	err = global.OC_DB.Transaction(func(tx *gorm.DB) error {

		if err := tx.Where("username = ?", claims.Username).First(&SearchAccount).Error; err != nil {
			return errors.New("无该账户信息")
		} else {
			tx.Scopes(dao.GetAccountDao.GetAccountList(SearchAccount, paginate, tx)).Find(&accounts).Scopes(dao.GetCount(tx)).Count(&paginate.Total)

			paginate.Data = accounts

			return nil

		}
	})

	return &paginate.Page, err
}

func (a *Account) GetAreaByAccount(claims tools.BaseClaims) (ManageRegions []*admin.Region, err error) {

	var SearchAccount *admin.Account

	var rootRegions []*admin.Region

	err = global.OC_DB.Transaction(func(tx *gorm.DB) error {

		if err := tx.Where("username = ?", claims.Username).First(&SearchAccount).Error; err != nil {
			return errors.New("无该账号信息")
		} else {

			// if !SearchAccount.IsSetRegion {
			// 	return errors.New("未设置区域")
			// }
			var ids = utils.BeLongCity(SearchAccount.RegionLink)
			// 搜索区域
			tx.Find(&rootRegions, ids)
			tx.Where("link LIKE ?", fmt.Sprintf("%v%%", SearchAccount.RegionLink)).Omit("link").Find(&ManageRegions)
			ManageRegions = utils.BuildRegionForest(ManageRegions)

			return nil
		}
	})

	return ManageRegions, err
}

// 根据账号获取他的子角色
func (a *Account) GetRoleByAccount(claims tools.BaseClaims) (roles []*admin.Role, err error) {

	var SearchAccount *admin.Account

	var parse *utils.ParseAccount

	err = global.OC_DB.Transaction(func(tx *gorm.DB) error {

		err1 := tx.Scopes(parse.Parse(claims, tx)).First(&SearchAccount).Error

		if err1 != nil {
			return errors.New("无该账号信息")
		}

		tx.Where("p_id = ?", SearchAccount.RoleId).Omit("link").Find(&roles)

		return nil

	})

	return roles, err
}

// 获取账号当前可以设置的区域
func (a *Account) GetCanSetRegionByAccount(claims tools.BaseClaims) (regions []*admin.Region, err error) {

	var SearchAccount *admin.Account

	var parse *utils.ParseAccount

	err = global.OC_DB.Transaction(func(tx *gorm.DB) error {

		err1 := tx.Scopes(parse.Parse(claims, tx)).First(&SearchAccount).Error

		if err1 != nil {
			return errors.New("无该账号信息")
		}

		var newReg = fmt.Sprintf("(%v)$", SearchAccount.RegionLink)

		tx.Where("link REGEXP ?", newReg).Omit("link").Find(&regions)

		return nil

	})

	return regions, err
}

// 删除
func (a *Account) Delete(ids []int, claims tools.BaseClaims) (err error) {

	var account *admin.Account

	var accounts []*admin.Account

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("无该账号信息")
	}

	global.OC_DB.Find(&accounts, ids)

	if !utils.IsBelongThisAccount(accounts, account) {
		return errors.New("你无权删除该账号")
	}

	global.OC_DB.Unscoped().Delete(&admin.Account{}, ids)

	return nil

}

func (a *Account) SetStatus(info *request.SetStatus, claims tools.BaseClaims) (err error) {

	var account *admin.Account

	var setAccount *admin.Account

	err = global.OC_DB.Scopes(dao.ParseAccountDao.Parse(claims, global.OC_DB)).First(&account).Error

	if err != nil {
		return errors.New("无该账号信息")
	}

	err = global.OC_DB.First(&setAccount, info.ID).Error

	if err != nil {
		return errors.New("位置错误500")
	}

	match, _ := regexp.MatchString(fmt.Sprintf("(^%v)", account.AccountLink), setAccount.AccountLink)

	if !match {
		return errors.New("你无权设置该账号")
	}

	global.OC_DB.Model(&admin.Account{}).Where("id = ?", info.ID).Update("status", info.Status)

	return nil

}

// 生成二维码
func (*Account) GenerateQRcode(claims tools.BaseClaims, id int) (qrcode string, err error) {

	account, err := base.FindAccount(claims, global.OC_DB)
	if err != nil {
		return "", err
	}

	var child *admin.Account

	global.OC_DB.First(&child, id)

	match, _ := regexp.MatchString(fmt.Sprintf("^%v", account.AccountLink), child.AccountLink)

	if !match {
		return "", errors.New(e.NoRightToFixThisAccount)
	}

	if errors.Is(err, gorm.ErrRecordNotFound) {
		return "", errors.New(e.AccountNotExist)
	}

	var qr_url string

	if child.Qrcode == "" {

		qr_url = wapi.WeiXinAccount.GenerateQrCode(global.OC_CONFIG.WeiXin.ExpiredTime, global.OC_CONFIG.WeiXin.QRType, child.Phone)

		// 重新生成二维码
		err = global.OC_DB.Model(&admin.Account{}).Where("id = ?", child.ID).Update("qrcode", qr_url).Error

		if errors.Is(err, gorm.ErrRecordNotFound) {
			return "", errors.New("未知错误500")
		}

	}

	return qr_url, nil

}

var AccountService = new(Account)
